/// <reference lib="dom" />
import axios from 'axios';

// 全局配置
// 超时时间10s
axios.defaults.timeout = 10000;

interface RequestQueue {
    [key: string]: AbortController;
}

const reqQueue: RequestQueue = {};

// 扩展的请求配置接口
interface ExtendedConfig {
    cancel?: boolean;
    key?: string;
    headers?: any;
    method?: string;
    url?: string;
    signal?: AbortSignal;
    [key: string]: any;
}

// 请求拦截器
axios.interceptors.request.use(function (config: any) {
    const extendedConfig = config as ExtendedConfig;
    const result = cancelReq(extendedConfig);
    return result as any;
}, function (error: any) {
    return Promise.reject(error);
});

// 响应拦截器
axios.interceptors.response.use(function (response: any) {
    let key = `${response.config.method}_${response.config.headers['Content-Type'] ? response.config.headers['Content-Type'] : ''}_${response.config.url}`;
    if (response.config['key']) {
        key += `_${response.config['key']}`;
    }
    if (reqQueue[key]) {
        delete reqQueue[key];
        console.log('reqQueue111', reqQueue);
    }
    return response;
}, function (error: any) {
    return Promise.reject(error);
});

// 取消请求
function cancelReq(config: ExtendedConfig): ExtendedConfig {
    if (config['cancel']) {
        const controller = new AbortController();
        let key = `${config.method}_${config.headers?.['Content-Type'] ? config.headers['Content-Type'] : ''}_${config.url}`;
        if (config['key']) {
            key += `_${config['key']}`;
        }
        if (reqQueue[key]) {
            reqQueue[key].abort();
            delete reqQueue[key];
        }
        config.signal = controller.signal;
        reqQueue[key] = controller;
    }
    return config;
}

// HTTP 请求方法参数类型
interface HttpParams {
    [key: string]: any;
}

interface HttpExtra {
    [key: string]: any;
}

// HTTP 服务接口
interface HttpService {
    get: (url: string, params?: HttpParams, extra?: HttpExtra) => Promise<any>;
    post: (url: string, params?: HttpParams, extra?: HttpExtra) => Promise<any>;
    postForm: (url: string, params?: HttpParams, extra?: HttpExtra) => Promise<any>;
    put: (url: string, params?: HttpParams, extra?: HttpExtra) => Promise<any>;
    putForm: (url: string, params?: HttpParams, extra?: HttpExtra) => Promise<any>;
    delete: (url: string, params?: HttpParams, extra?: HttpExtra) => Promise<any>;
    GetDownload: (url: string, params?: HttpParams, extra?: HttpExtra) => Promise<any>;
    upload: (url: string, params?: HttpParams, extra?: HttpExtra) => Promise<any>;
}

// 普通请求
const http: HttpService = {
    get: (url: string, params: HttpParams = {}, extra?: HttpExtra) => {
        return axios({
            url: url,
            method: 'get',
            params: params,
            ...extra
        }).catch((error: any) => {
            console.log(error);
            return new Promise((resolve) => {
                resolve(error);
            });
        });
    },
    // 默认post采用json形式
    post: (url: string, params: HttpParams = {}, extra: HttpExtra = {}) => {
        let conf: HttpExtra = {
            headers: {
                'Content-Type': 'application/json'
            }
        };
        conf = Object.assign(conf, extra);
        return axios({
            url: url,
            data: params,
            method: 'post',
            ...conf
        }).catch((error: any) => {
            console.log(error);
            return new Promise((resolve) => {
                resolve(error);
            });
        });
    },
    // 表单形式post
    postForm: (url: string, params: HttpParams = {}, extra: HttpExtra = {}) => {
        let conf: HttpExtra = {
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            }
        };
        conf = Object.assign(conf, extra);
        return axios({
            url: url,
            data: params,
            method: 'post',
            ...conf
        }).catch((error: any) => {
            console.log(error);
            return new Promise((resolve) => {
                resolve(error);
            });
        });
    },
    put: (url: string, params: HttpParams = {}, extra: HttpExtra = {}) => {
        let conf: HttpExtra = {
            headers: {
                'Content-Type': 'application/json'
            }
        };
        conf = Object.assign(conf, extra);
        return axios({
            url: url,
            data: params,
            method: 'put',
            ...conf
        }).catch((error: any) => {
            console.log(error);
            return new Promise((resolve) => {
                resolve(error);
            });
        });
    },
    putForm: (url: string, params: HttpParams = {}, extra: HttpExtra = {}) => {
        let conf: HttpExtra = {
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            }
        };
        conf = Object.assign(conf, extra);
        return axios({
            url: url,
            data: params,
            method: 'put',
            ...conf
        }).catch((error: any) => {
            console.log(error);
            return new Promise((resolve) => {
                resolve(error);
            });
        });
    },
    delete: (url: string, params: HttpParams = {}, extra?: HttpExtra) => {
        return axios({
            url: url,
            method: 'delete',
            params: params,
            ...extra
        });
    },
    GetDownload: (url: string, params: HttpParams = {}, extra: HttpExtra = {}) => {
        let conf: HttpExtra = {
            responseType: 'blob'
        };
        conf = Object.assign(conf, extra);
        // 如果在内部处理了axios的结果，则需要套多一层promise，否则外部将得不到信息
        return new Promise((resolve, reject) => {
            axios({
                url: url,
                params: params,
                method: 'get',
                ...conf
            })
                .then((res: any) => {
                    const fileName = decodeURI(res.headers['content-disposition']?.split(';')[1]?.split('=')[1] || 'download');
                    const blob = new Blob([res.data]);
                    const link = document.createElement('a');
                    link.download = fileName;
                    link.style.display = 'none';
                    link.href = URL.createObjectURL(blob);
                    document.body.appendChild(link);
                    link.click();
                    URL.revokeObjectURL(link.href); // 释放URL 对象
                    document.body.removeChild(link);
                    resolve(true);
                })
                .catch((e: any) => {
                    reject(e.response?.data);
                });
        }).catch((error: any) => {
            console.log(error);
            return new Promise((resolve) => {
                resolve(error);
            });
        });
    },
    upload: (url: string, params: HttpParams = {}, extra: HttpExtra = {}) => {
        let conf: HttpExtra = {
            headers: {
                'Content-Type': 'multipart/form-data'
            }
        };
        conf = Object.assign(conf, extra);
        return axios({
            url: url,
            data: params,
            method: 'post',
            ...conf
        }).catch((error: any) => {
            console.log(error);
            return new Promise((resolve) => {
                resolve(error);
            });
        });
    }
};

export default http;